package com.xyy.saas.payment.controller;

import com.alibaba.fastjson.JSON;
import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigChangeListener;
import com.ctrip.framework.apollo.ConfigService;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.google.common.util.concurrent.RateLimiter;
import com.xyy.saas.payment.constants.Constants;
import com.xyy.saas.payment.constants.HttpStatus;
import com.xyy.saas.payment.exception.PaymentException;
import com.xyy.saas.payment.manage.cores.vo.ResultVO;
import com.xyy.saas.payment.pojo.bo.ReportPropertiesBo;
import com.xyy.saas.payment.pojo.bo.ReportQueryOrderBo;
import com.xyy.saas.payment.pojo.bo.ReportQueryOrderViewBo;
import com.xyy.saas.payment.service.report.ReportService;
import com.xyy.saas.payment.pojo.vo.ReportExportOrderVo;
import com.xyy.saas.payment.pojo.vo.ReportQueryOrderVo;
import com.xyy.saas.payment.util.ApolloUtil;
import com.xyy.saas.payment.util.DateUtil;
import com.xyy.saas.payment.util.ExportExcelUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.DependsOn;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 管理平台报表接口
 */
@RestController
@RequestMapping("/report")
@DependsOn({"apolloUtil"})
public class ReportController implements InitializingBean {

    private static Logger LOGGER = LoggerFactory.getLogger(ReportController.class);

    private int rateLimiterCreate = Integer.parseInt(ApolloUtil.getProperty("report_export_limiter"));

    private RateLimiter rateLimiter = RateLimiter.create(rateLimiterCreate);

    @Autowired
    private ReportService reportService;

    /** 报表-获取配置信息 */
    @PostMapping("/properties")
    public ResultVO<ReportPropertiesBo> reportProperties() {
        ReportPropertiesBo bo = new ReportPropertiesBo();
        try {
            bo = reportService.getReportProperties();
        } catch (Exception e) {
            LOGGER.error("ReportController#reportProperties query properties error", e);
        }
        return ResultVO.createSuccess(bo);
}

    /** 报表-查询订单 */
    @PostMapping("/queryOrder")
    public ResultVO<ReportQueryOrderBo> reportQueryOrder(@RequestBody ReportQueryOrderVo reportQueryOrderVo) {
        LOGGER.info("ReportController#reportQueryOrder begin reportQueryOrderVo:{}", JSON.toJSONString(reportQueryOrderVo));
        if (reportQueryOrderVo.getEndDate() == null && reportQueryOrderVo.getBeginDate() == null && reportQueryOrderVo.getBusinessOrderNo() == null && reportQueryOrderVo.getChannelTransactionNo() == null && reportQueryOrderVo.getTradeNo() == null) {
            return ResultVO.createParamError("^_^日期和订单号不可以同时为空");
        }
        if (reportQueryOrderVo.getBeginDate() != null && reportQueryOrderVo.getEndDate() != null) {
            if (!checkDate(reportQueryOrderVo.getBeginDate(), reportQueryOrderVo.getEndDate())) {
                return ResultVO.createParamError("^_^日期选择不可以超过31天");
            }
        }
        if (reportQueryOrderVo.getBeginDate() == null && reportQueryOrderVo.getEndDate() != null || reportQueryOrderVo.getBeginDate() != null && reportQueryOrderVo.getEndDate() == null) {
            return ResultVO.createParamError("^_^开始时间需要和结束时间相对应");
        }
        ReportQueryOrderBo reportQueryOrderBo = new ReportQueryOrderBo();
        try {
            reportQueryOrderBo = reportService.reportQueryOrder(reportQueryOrderVo);
            LOGGER.info("ReportController#reportQueryOrder reportQueryOrderVo:{} reportQueryOrderBo:{}", JSON.toJSONString(reportQueryOrderVo), JSON.toJSONString(reportQueryOrderBo));
        } catch (Exception e) {
            LOGGER.error("ReportController#reportQueryOrder query order error reportQueryOrderVo:{}", JSON.toJSONString(reportQueryOrderVo),e);
        }
        return ResultVO.createSuccess(reportQueryOrderBo);
    }

    /** 报表-导出订单 */
    @PostMapping("/export")
    public void reportExportOrder(@RequestBody ReportExportOrderVo reportExportOrderVo,
                                  HttpServletRequest request,
                                  HttpServletResponse response) {
        // 尝试获取令牌
        if (!rateLimiter.tryAcquire(1)) {
            LOGGER.warn("ReportController#reportExportOrder refuse reportExportOrderVo:{}", JSON.toJSON(reportExportOrderVo));
            response.setStatus(HttpStatus.SYSTEM_BUSY);
            return;
        }
        if (reportExportOrderVo.getEndDate() == null && reportExportOrderVo.getBeginDate() == null && reportExportOrderVo.getBusinessOrderNo() == null && reportExportOrderVo.getChannelTransactionNo() == null && reportExportOrderVo.getTradeNo() == null) {
            //参数错误http状态码
            response.setStatus(HttpStatus.PARAM_ERROR);
            return;
        }
        if (reportExportOrderVo.getOrderType() == null) {
            response.setStatus(HttpStatus.PARAM_ERROR);
            return;
        }
        if (reportExportOrderVo.getBeginDate() != null && reportExportOrderVo.getEndDate() != null) {
            if (!checkDate(reportExportOrderVo.getBeginDate(), reportExportOrderVo.getEndDate())) {
                response.setStatus(HttpStatus.PARAM_ERROR);
                return;
            }
        }
        if (reportExportOrderVo.getBeginDate() == null && reportExportOrderVo.getEndDate() != null || reportExportOrderVo.getBeginDate() != null && reportExportOrderVo.getEndDate() == null) {
            response.setStatus(HttpStatus.PARAM_ERROR);
            return;
        }
        LOGGER.info("ReportController#reportExportOrder begin reportExportOrderVo:{}", JSON.toJSONString(reportExportOrderVo));
        try {
            List<ReportQueryOrderViewBo> results = null;
            try {
                results = reportService.reportExportOrderVo(reportExportOrderVo);
            } catch (PaymentException e) {
                LOGGER.warn("ReportController#reportExportOrder data too much error", e);
                response.setStatus(HttpStatus.DATA_MAX);
                return;
            }
            String excelFileName = reportService.buildExcelFileName(reportExportOrderVo);
            String sheetName = "订单信息表";
            String headers[] = Constants.ORDER_RECORD_EXCEL_HEADER;
            String fieldNames[] = Constants.ORDER_RECORD_EXCEL_FIELD;
            try {
                ExportExcelUtil.createExcelDateFormat(response, request, excelFileName, sheetName, headers, fieldNames, results, true, null);
                LOGGER.info("ReportController#reportExportOrder end reportExportOrderVo:{}", JSON.toJSONString(reportExportOrderVo));
            } catch (IOException e) {
                LOGGER.error("reportExportOrder excel导出错误{}", JSON.toJSONString(reportExportOrderVo), e);
            }
        } catch (Exception e) {
            LOGGER.error("ReportController#reportQueryOrder reportExportOrderVo order error reportExportOrderVo:{}", JSON.toJSONString(reportExportOrderVo),e);
        }
    }


    private boolean checkDate(Long beginDate, Long endDate) {
        String begin = DateUtil.getDayByDate(beginDate);
        String end = DateUtil.getDayByDate(endDate);
        int day = Integer.parseInt(end) - Integer.parseInt(begin);
        if (day > Constants.DATE_SELECT_MAX || day < 0) {
            return false;
        }
        return true;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        Set set = new HashSet();
        set.add("report_export_limiter");
        //动态监听配置变化
        Config config = ConfigService.getAppConfig();
        config.addChangeListener(new ConfigChangeListener() {
            @Override
            public void onChange(ConfigChangeEvent changeEvent) {
                rateLimiterCreate = Integer.parseInt(ApolloUtil.getProperty("report_export_limiter"));
                rateLimiter = RateLimiter.create(rateLimiterCreate);
                LOGGER.info("ReportController#onChange change rateLimiterCreate  success rateLimiterCreate:{} " , rateLimiterCreate);
            }
        }, set);
    }
}
